#pragma once

#include "Device.h"
#include "NeroEngine\NResource.h"

namespace Graphics
{
#ifdef DX_11
class Material;
struct MatrixBufferType
{
	D3DXMATRIX World;
	D3DXMATRIX View;
	D3DXMATRIX Projection;
};
class Shader : public Engine::NResource
{
private:
	RTTI_DECLARATIONS(Shader, Engine::NResource)

public:
	Shader(const std::string& instanceName, const std::string& filePath);
	virtual ~Shader(void);	
	virtual bool Initialize();
	virtual bool InitializeShader(D3DDevice* device, HWND winHandle, const char* vertexShaderName, const char*  pixelShaderName);
	virtual void Deinitialize();
	virtual bool SetShaderParameters(D3DDevice* device, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix);
	ID3D11VertexShader* GetVertexShader(){ return mVertexShader;}
	ID3D11PixelShader* GetPixelShader(){ return mPixelShader;}
	ID3D10Blob* GetVertexShaderBuffer(){return mVertexShaderBuffer;}
	ID3D10Blob* GetPixelShaderBuffer(){return mPixelShaderBuffer;}
	void SetLayout(ID3D11InputLayout* layout){mLayout = layout;}
	ID3D11InputLayout* GetLayout(){return mLayout;}

protected:
	virtual void DeinitializeShader();
	virtual bool RenderShader(D3DDevice* device, int indexCount);
	void OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, const char* shaderFilename);

protected:
	ID3D11VertexShader* mVertexShader;
	ID3D11PixelShader* mPixelShader;
	ID3D11InputLayout* mLayout;
	ID3D11Buffer* mMatrixBuffer;
	ID3D11SamplerState* mSampleState;
	ID3D10Blob* mVertexShaderBuffer;
	ID3D10Blob* mPixelShaderBuffer;
};

#endif
#ifdef DX_9
class Material;
class Shader : public Engine::NResource
{
	RTTI_DECLARATIONS(Shader, Engine::NResource)

public:
	typedef std::pair <const char*, D3DXHANDLE> TechniquePair;
	typedef std::hash_map <const char*, D3DXHANDLE> TechniqueList;
public:
	Shader(const std::string& instanceName, const std::string& filePath);
	
	virtual ~Shader(void);

	void Initialize();

	void Begin();

	void End();

	void InitializeTechniques();

	void Load(const char* filename);

	void SetCurrentTechnique(D3DXHANDLE technique);

	void SetEffect(LPD3DXEFFECT effect){mEffect = effect;}

	D3DXHANDLE CurrentTechnique(){return mCurrentTechnique;}

	LPD3DXEFFECT GetEffect(){return mEffect;}

	UINT PassCount(){return mPassCount;}

	TechniqueList Techniques(){return mTechniques;}
private:
	UINT mPassCount;

	LPD3DXEFFECT mEffect;

	D3DXHANDLE mCurrentTechnique;

	D3DXTECHNIQUE_DESC mCurrentTechDescription;

	TechniqueList mTechniques; //not being used fix that
};
class ShaderParameter
{
public:			
	ShaderParameter();

	ShaderParameter(Material* material, D3DXHANDLE handle, D3DXPARAMETER_DESC description);

	ShaderParameter(Material* material, D3DXHANDLE handle, D3DXPARAMETER_DESC description, void* value);

	ShaderParameter(Material* material, D3DXHANDLE handle, D3DXPARAMETER_DESC description, void* value, UINT count);

	~ShaderParameter(void);

	UINT GetCount();

	const D3DXPARAMETER_DESC& GetDescription();

	D3DXHANDLE GetHandle();

	void SetValue(void* value);

	void* GetValue();
	
	ShaderParameter& operator <<(D3DXMATRIX* value);
	ShaderParameter& operator <<(D3DXVECTOR2* value);
	ShaderParameter& operator <<(D3DXVECTOR3* value);
	ShaderParameter& operator <<(D3DXVECTOR4* value);
	ShaderParameter& operator <<(const D3DXMATRIX* value);
	ShaderParameter& operator <<(const D3DXVECTOR2* value);
	ShaderParameter& operator <<(const D3DXVECTOR3* value);
	ShaderParameter& operator <<(const D3DXVECTOR4* value);
	ShaderParameter& operator <<(FLOAT* value);
	ShaderParameter& operator <<(INT* value);
	ShaderParameter& operator <<(LPCSTR value);
	ShaderParameter& operator <<(LPDIRECT3DBASETEXTURE9 value);

private:
	UINT mCount;
	D3DXPARAMETER_DESC mDescription;
	D3DXHANDLE mHandle;
	Material* mMaterial;
	void* mValue;
};

#endif
}